local MAX_BUFFS = 6
local L = AceLibrary("AceLocale-2.2"):new("GridBuffIcons")
local SML = AceLibrary:HasInstance("SharedMedia-1.0") and AceLibrary("SharedMedia-1.0") or nil
local AceOO = AceLibrary("AceOO-2.0")

local petbars = false

GridBuffIconStatus = GridStatus:NewModule("GridBuffIconStatus")

GridBuffIconStatus.menuName = L["Buff Icons"]

GridBuffIconStatus.defaultDB = {
	debug = false,
	iconsize = 9,
	offsetx = 9,
	offsety = -1,
	alpha = 0.8,
	iconnum = 4,
	iconperrow = 2,
	showbuff = nil, 
	bufffilter = true,
	namefilter = nil,
	orientation = "VERTICAL",
	anchor = "TOPRIGHT",
	color = { r = 0, g = 0.5, b = 1.0, a = 1.0 },
	ecolor = { r = 1, g = 1, b = 0, a = 1.0 },
	rcolor = { r = 1, g = 0, b = 0, a = 1.0 },
	unit_buff_icons = {
		color = { r=1, g=1, b=1, a=1 },
		text = "BuffIcons",
		enable = true,
		priority = 30,
		range = false
	} 
}

GridBuffIconStatus.options = false

local buff_icons_options = {
	["Show Buff Not Debuff"] = {
		order = 50,
		type = "toggle",
		name = L["Show Buff instead of Debuff"],
		desc = L["If selected, the icons will present unit buffs instead of debuffs."],
		get = function()
			return GridBuffIconStatus.db.profile.showbuff;
		end,
		set = function(v)
			GridBuffIconStatus.db.profile.showbuff = v;
			GridBuffIconStatus:UpdateAllUnitsBuffs();
		end,
	},
	["Buff Filter"] = {
		order = 50,
		type = "toggle",
		name = L["Only castable/removable"],
		desc = L["If selected, only shows the buffs you can cast or the debuffs you can remove."],
		get = function()
			return GridBuffIconStatus.db.profile.bufffilter;
		end,
		set = function(v)
			GridBuffIconStatus.db.profile.bufffilter = v;
			GridBuffIconStatus:UpdateAllUnitsBuffs();
		end,
	},
	["Buff Name Filter"] = {
		order = 52,
		type = "text",
		name =  L["Buff Name Filter"],
		desc =  L["Buffs NOT TO show. Use '|' between the names."],
		get = function()
			return GridBuffIconStatus.db.profile.namefilter;
		end,
		usage =  "<buff name>",
		set = function(v) 
			GridBuffIconStatus.db.profile.namefilter = v;
			GridBuffIconStatus:UpdateAllUnitsBuffs();
		end,
	},
	["Icons size"] = {
		order = 55,
		type = "range",
		name = L["Icons Size"],
		desc = L["Size for each buff icon"],
		max = 16,
		min = 5,
		step = 1,
		get = function () return GridBuffIconStatus.db.profile.iconsize end,
		set = function(v)
			GridBuffIconStatus.db.profile.iconsize = v;
			GridFrame:WithAllFrames(function (f) f:ResetBuffIconSize() end)
		end
	},
	["Offset X"] = {
		order = 60,
		type = "range",
		name = L["Offset X"],
		desc = L["X-axis offset from the selected anchor point, minus value to move inside."],
		max = 20,
		min = -20,
		step = 1,
		get = function () return GridBuffIconStatus.db.profile.offsetx end,
		set = function(v)
			GridBuffIconStatus.db.profile.offsetx = v;
			GridFrame:WithAllFrames(function (f) f:ResetBuffIconPos() end)
		end
	},
	["Offset Y"] = {
		order = 65,
		type = "range",
		name = L["Offset Y"],
		desc = L["Y-axis offset from the selected anchor point, minus value to move inside."],
		max = 20,
		min = -20,
		step = 1,
		get = function () return GridBuffIconStatus.db.profile.offsety end,
		set = function(v)
			GridBuffIconStatus.db.profile.offsety = v;
			GridFrame:WithAllFrames(function (f) f:ResetBuffIconPos() end)
		end
	},
	["Alpha"] = {
		order = 70,
		type = "range",
		name = L["Alpha"],
		desc = L["Alpha value for each buff icon"],
		max = 1,
		min = 0.1,
		step = 0.1,
		get = function () return GridBuffIconStatus.db.profile.alpha end,
		set = function(v)
			GridBuffIconStatus.db.profile.alpha = v;
			GridFrame:WithAllFrames(function (f) f:ResetBuffIconAlpha() end)
		end
	},
	["Icon Numbers"] = {
		order = 75,
		type = "range",
		name = L["Icon Numbers"],
		desc = L["Max icons to show."],
		max = MAX_BUFFS,
		min = 1,
		step = 1,
		get = function()
			return GridBuffIconStatus.db.profile.iconnum;
		end,
		set = function(v)
			GridBuffIconStatus.db.profile.iconnum = v;
			GridBuffIconStatus:UpdateAllUnitsBuffs();
		end,
	},
	["Icons Per Row"] = {
		order = 75,
		type = "range",
		name = L["Icons Per Row"],
		desc = L["Sperate icons in several rows."],
		max = MAX_BUFFS,
		min = 0,
		step = 1,
		get = function()
			return GridBuffIconStatus.db.profile.iconperrow;
		end,
		set = function(v)
			GridBuffIconStatus.db.profile.iconperrow = v;
			GridFrame:WithAllFrames(function (f) f:ResetBuffIconPos() end);
		end,
	},
	["orientation"] = {
		order = 80;
		type = "text",
		name = L["Orientation of Icon"],
		desc = L["Set icons list orientation."],
		get = function ()
			      return GridBuffIconStatus.db.profile.orientation
			end,
		set = function (v)
			      GridBuffIconStatus.db.profile.orientation = v
			      GridFrame:WithAllFrames(function (f) f:ResetBuffIconPos() end)
			end,
		validate={["HORIZONTAL"] = L["HORIZONTAL"], ["VERTICAL"] = L["VERTICAL"]}
	},
	["anchor"] = {
		order = 80;
		type = "text",
		name = L["Anchor Point"],
		desc = L["Anchor point of the first icon."],
		get = function ()
			      return GridBuffIconStatus.db.profile.anchor
			end,
		set = function (v)
			      GridBuffIconStatus.db.profile.anchor = v
			      GridFrame:WithAllFrames(function (f) f:ResetBuffIconPos() end)
			end,
		validate={["TOPRIGHT"] = L["TOPRIGHT"], ["TOPLEFT"] = L["TOPLEFT"], ["BOTTOMLEFT"] = L["BOTTOMLEFT"], ["BOTTOMRIGHT"] = L["BOTTOMRIGHT"]}
	},
}
--local statusmap = GridFrame.db.profile.statusmap
local statusmap = GridFrame.defaultDB.statusmap
if not statusmap["bufficons"] then 
	statusmap["bufficons"] = {
		unit_buff_icons = true,
	}
end

if(GridFrame and GridFrame.db and GridFrame.db.profile) then
	statusmap = GridFrame.db.profile.statusmap
	if ( not statusmap["bufficons"] ) then
		statusmap["bufficons"] = {
			unit_buff_icons = true,
		}
	end
end

-- hooking stuff, taken from GridSideIndicators
local GridFrameClass = AceOO.Class(GridFrame.frameClass)

local _frameClass = nil
if ( not _frameClass ) then
	_frameClass = GridFrame.frameClass
	GridFrame.frameClass = GridFrameClass
end

function GridFrameClass.prototype:SetIndicator(indicator, color, text, value, maxValue, texture, start, duration, stack)
	if indicator == "bufficons" then
		if not self.frame[indicator] then
			self:CreateIndicator(indicator)
		end
	end
	GridFrameClass.super.prototype.SetIndicator(self,indicator, color, text, value, maxValue, texture, start, duration, stack)
end

function GridFrameClass.prototype:CreateFrames()
	GridFrameClass.super.prototype.CreateFrames(self)
	
	local f = self.frame
	f.BuffIcons = {};
	for i=1, MAX_BUFFS do
		f.BuffIcons[i] = f.Bar:CreateTexture("BuffIcon"..i, "OVERLAY");
		f.BuffIcons[i]:SetTexCoord(0.05, 0.95, 0.05, 0.95)
		f.BuffIcons[i]:SetTexture(1,1,1,0)
	end

	self:ResetBuffIconSize();
	self:ResetBuffIconPos();
	self:ResetBuffIconAlpha();
end

function GridFrameClass.prototype:ResetBuffIconSize()
	local f = self.frame;
	if(f.BuffIcons) then
		for _,v in pairs(f.BuffIcons) do
			v:SetWidth(GridBuffIconStatus.db.profile.iconsize);
			v:SetHeight(GridBuffIconStatus.db.profile.iconsize);
		end
	end
end

function GridFrameClass.prototype:ResetBuffIconPos()
	local f = self.frame;
	local icons = f.BuffIcons
	local xadjust = 1;
	local yadjust = 1;
	local p = GridBuffIconStatus.db.profile;
	if(string.find(p.anchor, "BOTTOM")) then yadjust = -1; end;
	if(string.find(p.anchor, "LEFT")) then xadjust = -1; end;
	if(icons) then
		for k,v in pairs(icons) do
			v:ClearAllPoints();
			if(k==1) then
				v:SetPoint(p.anchor, f, p.anchor, xadjust * p.offsetx, yadjust * p.offsety)
			elseif(p.iconperrow and p.iconperrow>0 and (k-1)%p.iconperrow==0) then
				if(p.orientation == "VERTICAL") then
					if(string.find(p.anchor, "RIGHT")) then
						if(p.offsetx<=0) then
							v:SetPoint("RIGHT", icons[k-p.iconperrow], "LEFT", -1, 0); --向内侧(左)
						else
							v:SetPoint("LEFT", icons[k-p.iconperrow], "RIGHT", 1, 0);  --向外侧(右)
						end
					elseif(string.find(p.anchor, "LEFT")) then
						if(p.offsetx<=0) then
							v:SetPoint("LEFT", icons[k-p.iconperrow], "RIGHT", 1, 0);  --向内侧(右)
						else
							v:SetPoint("RIGHT", icons[k-p.iconperrow], "LEFT", -1, 0);
						end
					end
				else
					if(string.find(p.anchor, "TOP")) then
						if(p.offsety<=0) then
							v:SetPoint("TOP", icons[k-p.iconperrow], "BOTTOM", 0, -1);  --向内侧(下)
						else
							v:SetPoint("BOTTOM", icons[k-p.iconperrow], "TOP", 0, 1);  --向内侧(上)
						end
					elseif(string.find(p.anchor, "BOTTOM")) then
						if(p.offsety<=0) then
							v:SetPoint("BOTTOM", icons[k-p.iconperrow], "TOP", 0, 1);
						else
							v:SetPoint("TOP", icons[k-p.iconperrow], "BOTTOM", 0, -1);
						end
					end
				end
			else
				if(p.orientation == "VERTICAL") then
					if(string.find(p.anchor, "BOTTOM")) then
						v:SetPoint("BOTTOM", icons[k-1], "TOP", 0, 1);  --向上增长
					else
						v:SetPoint("TOP", icons[k-1], "BOTTOM", 0, -1); --向下增长
					end
				else
					if(string.find(p.anchor, "LEFT")) then
						v:SetPoint("LEFT", icons[k-1], "RIGHT", 1, 0);  --向右增长
					else
						v:SetPoint("RIGHT", icons[k-1], "LEFT", -1, 0);  --向左增长
					end
				end
			end
		end
	end
end

function GridFrameClass.prototype:ResetBuffIconAlpha()
	local f = self.frame;
	if(f.BuffIcons) then
		for k,v in pairs(f.BuffIcons) do
			v:SetAlpha( GridBuffIconStatus.db.profile.alpha );
		end
	end
end

function GridBuffIconStatus:OnInitialize()
	self.super.OnInitialize(self)
	self:RegisterStatus('unit_buff_icons',L["Buff Icons"], buff_icons_options, true)

	--hook the enable option
	GridStatus.options.args["unit_buff_icons"].args["enable"].set = function (value)
		GridBuffIconStatus.db.profile["unit_buff_icons"].enable = value;
		if(value)then
			GridBuffIconStatus:UpdateAllUnitsBuffs();
		else
			for k,v in pairs(GridFrame.registeredFrames) do
				if(v.frame.BuffIcons) then
					for i=1, MAX_BUFFS do v.frame.BuffIcons[i]:SetTexture(nil); end
				end
			end
		end
	end;
end

function GridBuffIconStatus:OnEnable()
	self:RegisterEvent("UNIT_AURA")
	--self:RegisterEvent("Grid_UnitJoined")
	--self:RegisterEvent("PARTY_MEMBERS_CHANGED", "UpdateAllUnitsBuffs")
	--self:RegisterEvent("Grid_UpdateLayoutSize", "UpdateAllUnitsBuffs");
	self:RegisterBucketEvent("Grid_UpdateLayoutSize", 1, "UpdateAllUnitsBuffs")

	self:UpdateAllUnitsBuffs();
end

function GridBuffIconStatus:UNIT_AURA(unitid)
	if(not GridBuffIconStatus.db.profile["unit_buff_icons"].enable) then return; end;

	local guid = UnitGUID(unitid)
	if not GridRoster:IsGUIDInRaid(guid) then
		return
	end

	--if(not u or string.find(unitid, "pet")) then return; end;
	local namefilter = {strsplit("||", GridBuffIconStatus.db.profile.namefilter or "")}
	--self.core:SendStatusGained(u.name, "unit_buff_icons", 99, nil,nil,nil,cur,max,nil)
	for k,v in pairs(GridFrame.registeredFrames) do
		if v.unitGUID == guid then
			if(not v.frame.BuffIcons) then
				v:CreateIndicator("bufficons");
			end

			local i = 1
			local n = 1
			while(n <= GridBuffIconStatus.db.profile.iconnum and i<40) do
				local name, rank, iconTexture, count, duration, timeLeft;
				if GridBuffIconStatus.db.profile.showbuff then 
					name, rank, iconTexture, count, duration, timeLeft = UnitBuff(unitid, i, GridBuffIconStatus.db.profile.bufffilter and "RAID");
				else
					name, rank, iconTexture, count, duration, timeLeft = UnitDebuff(unitid,i, GridBuffIconStatus.db.profile.bufffilter and "RAID");
				end
				if(name) then
					local flag = true
					for k,v in pairs(namefilter) do
						if(name==v) then
							flag = false;
							break;
						end
					end
					if(flag)then
						v.frame.BuffIcons[n]:SetTexture(iconTexture);
						n=n+1
					end
				else
					break;
				end
				i=i+1
			end
			for i=n, MAX_BUFFS do
				v.frame.BuffIcons[i]:SetTexture(nil);
			end
--[[
			for i=1, MAX_BUFFS do
				if(not v.frame.BuffIcons) then
					v:CreateIndicator("bufficons");
				end
				v.frame.BuffIcons[i]:SetTexture(nil);
				if(GridBuffIconStatus.db.profile.iconnum >= i) then
					local name, rank, iconTexture, count, duration, timeLeft;
					if GridBuffIconStatus.db.profile.showbuff then 
						name, rank, iconTexture, count, duration, timeLeft = UnitBuff(unitid, i, GridBuffIconStatus.db.profile.bufffilter and "RAID");
					else
						name, rank, iconTexture, count, duration, timeLeft = UnitDebuff(unitid,i, GridBuffIconStatus.db.profile.bufffilter and "RAID");
					end
					if(name) then
						v.frame.BuffIcons[i]:SetTexture(iconTexture);
					end
				end
			end
]]
		end
	end
end

function GridBuffIconStatus:Grid_UnitJoined(guid, unitid)
	for k,v in pairs(GridFrame.registeredFrames) do
		if v.guid == guid then
			v.unitid = unitid
			self:UNIT_AURA(unitid)
		end
	end
end

function GridBuffIconStatus:UpdateAllUnitsBuffs()
	for guid, unitid in GridRoster:IterateRoster() do
		self:UNIT_AURA(unitid)
	end
	--self:UNIT_AURA("player");
end